import java.awt.Color;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.Collection;


public class Soldier implements Selectable, ActionListener{

	private static final int WIDTH = 10;
	private static final int HEIGHT = 20;
	private double x, y;
	private int width = 10, height = 20;
	private int boundry = 10;
	private double targetX;
	private double targetY;
	private boolean selected;
	private static final Color SELECTED = Color.GREEN;
	private static final Color UNSELECTED = Color.RED;
	private int priority;
	private static int priorityLevels = 0;
	private Collection<Selectable>otherUnits;
	public Soldier(Collection<Selectable>others){
		otherUnits = others;
		priority = priorityLevels;
	}
	
	public Soldier(Collection<Selectable>others, int x, int y){
		this(others);
		this.targetX = this.x = x;
		this.targetY = this.y = y;
	}


	@Override
	public boolean isIntersected(int x, int y, int x2, int y2) {
		return pointIn(x, y, this.x - width, this.y - height, this.x + width, this.y + height) ||
				pointIn(x2, y, this.x- width, this.y- height, this.x + width, this.y + height) ||
				pointIn(x, y2, this.x- width, this.y- height, this.x + width, this.y + height) ||
				pointIn(x2, y2, this.x- width, this.y- height, this.x + width, this.y + height) ||
				pointIn(this.x- width, this.y- height, x, y, x2, y2) ||
				pointIn(this.x + width, this.y- height, x, y, x2, y2) ||
				pointIn(this.x- width, this.y + height, x, y, x2, y2) ||
				pointIn(this.x + width, this.y + height, x, y, x2, y2);
	}
	
	private boolean pointIn(int x, int y, int startX, int startY, int endX, int endY){
		return (x >= startX && x <= endX && y >= startY && y<= endY);
	}

	private boolean pointIn(double x, double y, int startX, int startY, int endX, int endY){
		return (x >= startX && x <= endX && y >= startY && y<= endY);
	}
	
	private boolean pointIn(int x, int y, double startX, double startY, double endX, double endY){
		return (x >= startX && x <= endX && y >= startY && y<= endY);
	}
	
	private boolean pointIn(double x, double y, double startX, double startY, double endX, double endY){
		return (x >= startX && x <= endX && y >= startY && y<= endY);
	}
	@Override
	public boolean isInBoundry(int x, int y, int x2, int y2) {
		return pointIn(x, y, this.x- width, this.y- height, this.x + width, this.y + height) || 
				pointIn(x2, y, this.x- width, this.y- height, this.x + width, this.y + height) ||
		pointIn(x, y2, this.x- width, this.y- height, this.x + width, this.y + height) ||
		pointIn(x2, y2, this.x- width, this.y- height, this.x + width, this.y + height) ||
		pointIn(this.x- width, this.y- height, x, y, x2, y2) ||
		pointIn(this.x + width, this.y- height, x, y, x2, y2) ||
		pointIn(this.x- width, this.y + height, x, y, x2, y2) ||
		pointIn(this.x + width, this.y + height, x, y, x2, y2);
	}
	@Override
	public boolean isInBoundry(double x, double y, double x2, double y2) {
		return pointIn(x, y, this.x - width, this.y - height, this.x + width, this.y + height) || 
				pointIn(x2, y, this.x- width, this.y- height, this.x + width, this.y + height) ||
		pointIn(x, y2, this.x- width, this.y- height, this.x + width, this.y + height) ||
		pointIn(x2, y2, this.x- width, this.y- height, this.x + width, this.y + height) ||
		pointIn(this.x- width, this.y- height, x, y, x2, y2) ||
		pointIn(this.x + width, this.y- height, x, y, x2, y2) ||
		pointIn(this.x- width, this.y + height, x, y, x2, y2) ||
		pointIn(this.x + width, this.y + height, x, y, x2, y2);
	}

	
	
	@Override
	public void sendTo(double x, double y) {
		targetX = x;
		targetY = y;

	}

	private static final double SPEED = 2.5; 
	
	@Override
	public void actionPerformed(ActionEvent arg0) {
		
		double delX = targetX - x;
		double delY = targetY - y;
		double hyp = Math.hypot(delX, delY);
		double moveX = delX/hyp;
		double moveY = delY/hyp;
		boolean willCollide = false;
		if(otherUnits != null){
			for(Selectable other: otherUnits){
				willCollide = willCollide || this.isColliding(other) && this.getPriority() <= other.getPriority();
			}
		}
		if(!(Double.isNaN(moveX) || Double.isNaN(moveY)) && hyp >= SPEED && !willCollide){
			x += moveX * SPEED;
			y += moveY * SPEED;
		}

	}

	@Override
	public Color getColor() {
		return (selected)? SELECTED:UNSELECTED;
	}

	@Override
	public Shape[] getShapes() {
		double delX = targetX - x;
		double delY = targetY - y;
		double hyp = Math.hypot(delX, delY);
		double moveX = delX/hyp;
		double moveY = delY/hyp;
		return new Shape[]{new Rectangle2D.Double(x - width, y - height, 2*width, 2*height), new Ellipse2D.Double(x + moveX * SPEED, y + moveY * SPEED, 5, 5)};
	}

	@Override
	public void becomeSelected() {
		selected = true;

	}

	@Override
	public void becomeUnselected() {
		selected = false;

	}
	
	public int getPriority(){
		return priority;
	}

	@Override
	public boolean isInDirection(double x, double y, double x2, double y2, double xDir, double yDir) {
		return (new Ellipse2D.Double(x + xDir, y + yDir, x2-x, y2-y)).contains(this.x-width, this.y-height, this.x + width, this.y + height);
				
	}

	private static final double REDUCE_SCALE = .0003;
	@Override
	public Rectangle2D getCollisionTemplate() {
		double delX = targetX - x;
		double delY = targetY - y;
		double hyp = Math.hypot(delX, delY);
		double moveX = delX/hyp;
		double moveY = delY/hyp;
		return new Rectangle2D.Double(x + moveX*SPEED - width - hyp* REDUCE_SCALE, y + moveY*SPEED - height - hyp*REDUCE_SCALE, 2*width - hyp * 2 * REDUCE_SCALE, 2*height - hyp *2 * REDUCE_SCALE);
	}

	@Override
	public boolean isColliding(Collidable other) {
		
		return !this.equals(other) && this.getCollisionTemplate().intersects(other.getNormalShape());
		//return false;
	}
	@Override
	public Rectangle2D getNormalShape(){
		return new Rectangle2D.Double(x- width, y - height, 2*width, 2*height);
	}



}
